package priv.lhy.ecm.collectorProducer.task;

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import priv.lhy.ecm.collectorProducer.annotation.UploadJob;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.*;

/**
 * @author: lihy
 * date: 2019/6/20 14:54
 * description: 创建job列表
 */
@Configuration
public class JobsBuilder implements ResourceLoaderAware {

    //spring容器
    private ResourceLoader resourceLoader;

    @Autowired
    private Environment env;

    //job类所在包,可多个，使用","分割
    @Value("${job.package}")
    private String jobPackage;

    @Value("${job.cron.default}")
    private String defaultCron;

    /**
     * 生成job列表
     *
     * @return
     */
    @Bean("jobs")
    public Map<JobDetail, Set<? extends Trigger>> getJobs() {
        Map<JobDetail, Set<? extends Trigger>> jobs = new HashMap<>();
        try {
            String[] packages = jobPackage.split(",");
            List<Class> jobClassList = new ArrayList<>();
            for (int i = 0; i < packages.length; i++) {
                jobClassList.addAll(scanPackage(packages[i]));
            }

            for (Class clazz : jobClassList) {
                String name;
                String group;
                String[] cron;
                for (Annotation anno : clazz.getDeclaredAnnotations()) {
                    if (((UploadJob) anno).name().equals("")) {
                        throw new RuntimeException("必须定义job名称");
                    }
                    name = ((UploadJob) anno).name();

                    if (((UploadJob) anno).group().equals("")) {
                        throw new RuntimeException("必须定义job组");
                    }
                    group = ((UploadJob) anno).group();

                    //cron使用顺序
                    // 注解->application.name->application.group->application.defaultcron
                    if (!((UploadJob) anno).cron()[0].equals("")) {
                        cron = ((UploadJob) anno).cron();
                    } else if (null != env.getProperty("job.cron.name." + name)) {
                        cron = env.getProperty("job.cron.name." + name).split("\\|");
                    } else if (null != env.getProperty("job.cron.group." + group)) {
                        cron = env.getProperty("job.cron.group." + group).split("\\|");
                    } else if (null != defaultCron) {
                        cron = defaultCron.split("\\|");
                    } else {
                        throw new RuntimeException("必须定义job计划");
                    }

                    JobDetail detail = JobBuilder.newJob(clazz).withIdentity(name, group).build();

                    Set<Trigger> triggerSet = new HashSet<>();
                    for (int i = 0; i < cron.length; i++) {
                        CronTrigger trigger = TriggerBuilder.newTrigger()
                                .withIdentity(name + i, group)
                                .withSchedule(CronScheduleBuilder.cronSchedule(cron[i])).build();
                        triggerSet.add(trigger);
                    }

                    jobs.put(detail, triggerSet);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jobs;
    }

    /**
     * 获取job类
     *
     * @param classPath
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private List<Class> scanPackage(String classPath) throws IOException, ClassNotFoundException {
        List<Class> list = new ArrayList<>();
        //生产环境可能是jar模式运行，使用resource在jar包中获取类
        ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
        Resource[] resources = resolver.getResources("classpath*:" + classPath.replace(".",
                "/") + "/*.class");
        for (Resource r : resources) {
            MetadataReader reader = metadataReaderFactory.getMetadataReader(r);
            Class clazz = Class.forName(reader.getClassMetadata().getClassName());
            //只选择有job注解的类
            if (clazz.isAnnotationPresent(UploadJob.class)) {
                list.add(clazz);
            }
        }
        return list;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}
